

//OS
#include <jxos_config.h>
#include "kernel/jxos_task.h"
#include "kernel/jxos_event.h"
#include "kernel/jxos_msg.h"
//LIB
#include "../lib/sw_timer.h"

//SYS
#include "power_mgr_task.h"
#include "debug_print_task.h"

#if ((JXOS_TASK_ENABLE == 1)&&(JXOS_ENENT_ENABLE == 1)&&(JXOS_SYS_SERVICE_SOFTWARE_TIMER_TASK_ENABLE == 1))

void (*sys_software_timer_task_hal_init_callback)(void) = 0;
void (*sys_software_timer_task_hal_start_callback)(void) = 0;
void (*sys_software_timer_task_hal_stop_callback)(void) = 0;
uint16_t (*sys_software_timer_task_hal_set_next_interrupt_time_in_ms_callback)(uint16_t next_interrupt_time_in_ms) = 0;

#if (TIMER_DYNAMIC_CHANGE_ENABLE == 1)
uint16_t (*sys_software_timer_task_hal_get_passed_time_callback)(void) = 0;
#endif

/***********************************************************/
static JXOS_EVENT_HANDLE software_timer_task_tick_event;
static JXOS_EVENT_HANDLE software_timer_task_change_event;

static SW_TIMER_GROUP_STRUCT swt_group;
static SW_TIMER_STRUCT swt_space[SWTIMER_MAX];

static uint8_t tick_happened_falg = 0;

static uint8_t check_running_all(void)
{
	uint8_t i;
	for(i = 0; i < SWTIMER_MAX; i++){
		if(sw_timer_check_enable(&(swt_space[i])) != 0){
			break;
		}
	}
	if(i == SWTIMER_MAX){
		i = 0;
	}
	else{
		i = 1;
	}
	return i;
}

static uint16_t find_minimum_time(void)
{
	uint16_t min = 0xffff;
	uint8_t i;
	for(i = 0; i < SWTIMER_MAX; i++){
		if(sw_timer_check_enable(&(swt_space[i])) != 0){
			if(sw_timer_get_counter(&(swt_space[i])) < min){
				min = sw_timer_get_counter(&(swt_space[i]));
			}
		}
	}
	return min;
}

#if (TIMER_DYNAMIC_CHANGE_ENABLE == 1)
static void timer_change(void)
{
	uint16_t time = 0;

	//get passed time
	if(sys_software_timer_task_hal_get_passed_time_callback != 0){
		time = sys_software_timer_task_hal_get_passed_time_callback();
	}
	//swt_group refresh
	software_timer_group_handler(&swt_group, time);

	//calculate next_interrupt_time
	if(software_timer_group_check_running_all(&swt_group) != 0){
		time = software_timer_group_find_minimum_time(&swt_group);
	}
	else{
		time = 0;
		if(sys_software_timer_task_hal_stop_callback != 0){
			sys_software_timer_task_hal_stop_callback();
		}
	}
	//set next interrupt
	if(time != 0){
		if(sys_software_timer_task_hal_set_next_interrupt_time_in_ms_callback != 0){
			sys_software_timer_task_hal_set_next_interrupt_time_in_ms_callback(time);
		}
	}
}
#else
static void timer_change(void)
{
#ifdef TIMER_CONSTANT_INTERVAL_MS
	//swt_group refresh
	sw_timer_group_tick_handler(&swt_group, TIMER_CONSTANT_INTERVAL_MS);

	if(check_running_all() == 0){
		if(sys_software_timer_task_hal_stop_callback != 0){
			sys_software_timer_task_hal_stop_callback();
		}
	}
#else
	static uint16_t last_wakeup_time = 0;
	//swt_group refresh
	sw_timer_group_tick_handler(&swt_group, last_wakeup_time);

	//calculate next_interrupt_time
	if(check_running_all() != 0){
		last_wakeup_time = find_minimum_time();
	}
	else{
		last_wakeup_time = 0;
		if(sys_software_timer_task_hal_stop_callback != 0){
			sys_software_timer_task_hal_stop_callback();
		}
	}
	//set next interrupt
	if(last_wakeup_time != 0){
		if(sys_software_timer_task_hal_set_next_interrupt_time_in_ms_callback != 0){
			last_wakeup_time = sys_software_timer_task_hal_set_next_interrupt_time_in_ms_callback(last_wakeup_time);
		}
	}
#endif
}
#endif


static void software_timer_task(uint8_t task_id, void * parameter)
{
//	if(jxos_event_wait(software_timer_task_tick_event) == 1){
//		tick_happened_falg = 1;
//		timer_change();
//	}

	if(jxos_event_wait(software_timer_task_change_event) == 1){
		if(sys_software_timer_task_hal_start_callback != 0){
			sys_software_timer_task_hal_start_callback();
		}
		timer_change();
	}
}

uint8_t software_timer_task_get_tick_happened(void)
{
	return tick_happened_falg;
}

void software_timer_task_reset_tick_happened(void)
{
	tick_happened_falg = 0;
}

void software_timer_task_tick_handler(void)
{
//	jxos_event_set(software_timer_task_tick_event);
	tick_happened_falg = 1;
	timer_change();
}

void sys_software_timer_task_init(void)
{
	//HAL
	if(sys_software_timer_task_hal_init_callback != 0){
		sys_software_timer_task_hal_init_callback();
	}

	//BSP

	//OS
	jxos_task_create(software_timer_task, "swt_t", 0);
//	software_timer_task_tick_event = jxos_event_create();
	software_timer_task_change_event = jxos_event_create();
	
	//LIB
    sw_timer_group_init(&swt_group, SWTIMER_MAX, swt_space);

	if(sys_software_timer_task_hal_start_callback != 0){
		sys_software_timer_task_hal_start_callback();
	}
	
	//SYS TASK
}

/***********************************************************/
SW_TIMER_STRUCT* sys_software_timer_task_new_timer(void)
{
    SW_TIMER_STRUCT* swt;
	swt = sw_timer_new(&swt_group, 0, 0);
	if(swt == 0){
        sys_debug_print_task_sys_ser_print_str("create_new_timer error");
	}
	return swt;
}

void sys_software_timer_task_timer_overtime_callback_reg(SW_TIMER_STRUCT* swtime_id, void timer_overtime_callback(SW_TIMER_STRUCT* swtime_id))
{
	swtime_id->period_timeout_callback = timer_overtime_callback(swtime_id);
}

void sys_software_timer_task_set_timer(SW_TIMER_STRUCT* swtime_id, uint16_t time)
{
	sw_timer_set_period(swtime_id, time);
	jxos_event_set(software_timer_task_change_event);
}

void sys_software_timer_task_start_timer(SW_TIMER_STRUCT* swtime_id)
{
	sw_timer_enable(swtime_id);
	jxos_event_set(software_timer_task_change_event);
}

void sys_software_timer_task_stop_timer(SW_TIMER_STRUCT* swtime_id)
{
	sw_timer_disable(swtime_id);
}

void sys_software_timer_task_restart_timer(SW_TIMER_STRUCT* swtime_id)
{
	sw_timer_reset_counter(swtime_id);
	sw_timer_enable(swtime_id);
	jxos_event_set(software_timer_task_change_event);
}

uint8_t sys_software_timer_task_check_running_timer(SW_TIMER_STRUCT* swtime_id)
{
	return sw_timer_check_enable(swtime_id);
}

uint8_t sys_software_timer_task_check_overtime_timer(SW_TIMER_STRUCT* swtime_id)
{
	uint8_t ret = sw_timer_check_timeout(swtime_id);
	sw_timer_reset_timeout(swtime_id);
    return ret;
}

#endif
